package com.zmn.uac.business.impl.oauth.login;

import com.alibaba.fastjson.JSONObject;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.saas.dubbo.dto.app.AppDRO;
import com.zmn.uac.business.interfaces.oauth.login.JDLoginBService;
import com.zmn.uac.business.template.oauth.login.BaseLoginTemplateMode;
import com.zmn.uac.common.constant.AccessTypeConstant;
import com.zmn.uac.common.constant.JDConstant;
import com.zmn.uac.common.dio.oauth.login.TempCodeDIO;
import com.zmn.uac.common.dio.oauth.login.UserAuthLoginDIO;
import com.zmn.uac.common.entity.oauth.login.*;
import com.zmn.uac.common.entity.oauth.phone.UserPhoneInfo;
import com.zmn.uac.common.info.UserAuthPhoneInfo;
import com.zmn.uac.common.info.jd.JdAccessTokenInfo;
import com.zmn.uac.common.info.jd.JdUserInfo;
import com.zmn.uac.util.HttpClientsUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.Objects;
import java.util.TreeMap;


/**
 * 类描述：京东登陆业务实现
 *
 * @author xujie
 * @since 2021/05/19 17:44
 */
@Slf4j
@Service
public class JDLoginBServiceImpl extends BaseLoginTemplateMode implements JDLoginBService {

    private static final String TAG = "京东登陆业务实现";

    @Override
    public ResponseDTO<UserAuthLoginInfo> thirdPartyUserDataAcquisition(UserAuthLoginDIO dio,
                                                                        UserAuthPhoneInfo authPhoneInfo) {

        Integer channelId = dio.getChannelId();
        AppDRO app = Objects.equals(dio.getAccessType(), AccessTypeConstant.SHOP)
                ? getAppInfoByShopId(dio.getShopId()) : getAppByChannelId(channelId);
        if (Objects.isNull(app)) {
            return ResponseDTO.fail("查询应用为null");
        }
        String uuid = dio.getUuid();
        ResponseDTO<String> responseDTO = getOpenIdByCode(uuid, dio.getCode(), app.getThirdAppId(), app.getThirdAppSecret());
        if (!responseDTO.isSuccess()) {
            return ResponseDTO.fail(responseDTO.getMessage());
        }
        String openId = responseDTO.getData();
        UserInfo info = setUserInfo(openId, dio);
        PlatInfo platInfo = setPlatInfo(dio, app, channelId);
        ThirdAppInfo thirdAppInfo = setThirdAppInfo(app);
        UserAuthLoginInfo userAuthLoginInfo = setUserAuthLoginInfo(info, platInfo, thirdAppInfo, authPhoneInfo);

        return ResponseDTO.success(userAuthLoginInfo);
    }

    @Override
    public ResponseDTO<String> getThirdPartyOpenIdByCode(TempCodeDIO tempCodeDIO, AppDRO app) {
        ResponseDTO<String> responseDTO = getOpenIdByCode(null, tempCodeDIO.getCode(), app.getThirdAppId(), app.getThirdAppSecret());
        if (!responseDTO.isSuccess()) {
            return ResponseDTO.fail(responseDTO.getMessage());
        }
        log.info("获取钉钉调用响应responseDTO:{}", responseDTO.getData());
        return responseDTO;
    }

    /**
     * 通过code获取access_token
     *
     * @param uuid uuid
     * @param code code
     * @return JdAccessTokenInfo
     * @author xujie
     * @since 2021/05/20
     */
    private ResponseDTO<JdAccessTokenInfo> getAccessToken(String uuid, String code, String appKey, String appSecret) {
        String url = JDConstant.GET_ACCESS_TOKEN_URL + "?app_key=" + appKey +
                "&app_secret=" + appSecret + "&grant_type=" + JDConstant.GRANT_TYPE +
                "&code=" + code;
        String jsonString = HttpClientsUtil.executeGet(url);
        log.info("[{}], {}, 通过code获取 jd access_token, 返回信息：{}", TAG, uuid, jsonString);
        if (jsonString == null) {
            return ResponseDTO.fail("获取access token失败");
        }
        JdAccessTokenInfo jdAccessTokenInfo = JSONObject.parseObject(jsonString, JdAccessTokenInfo.class);
        if (Objects.nonNull(jdAccessTokenInfo) && StringUtil.isNotBlank(jdAccessTokenInfo.getAccessToken())) {
            return ResponseDTO.success(jdAccessTokenInfo);
        } else {
            log.error("[{}], {}, 通过code获取 jd access_token失败, 返回信息：{}", TAG, uuid, jsonString);
            JSONObject jsonObject = JSONObject.parseObject(jsonString);
            return ResponseDTO.fail(jsonObject.getString("msg"));
        }
    }

    /**
     * 查询用户openid
     *
     * @param uuid      uuid
     * @param code      code
     * @param appKey    appKey
     * @param appSecret appSecret
     * @return String
     * @author xujie
     * @since 2021/05/20
     */
    private ResponseDTO<String> getOpenIdByCode(String uuid, String code, String appKey, String appSecret) {
        String url = JDConstant.SESSION_URL + "?appid=" + appKey + "&secret=" + appSecret + "&code=" + code;
        String jsonString = HttpClientsUtil.executeGet(url);
        log.info("[{}], {}, 查询用户openid, 返回信息：{}", TAG, uuid, jsonString);
        if (jsonString == null) {
            return ResponseDTO.fail("获取用户openid失败");
        }
        String data = "data";
        JSONObject result = JSONObject.parseObject(jsonString);
        if (result.containsKey(data) && null != result.get(data)) {
            JSONObject dataJson = result.getJSONObject(data);
            String responseOpenId = "openId";
            if (dataJson.containsKey(responseOpenId)) {
                return ResponseDTO.success(dataJson.getString(responseOpenId));
            }
        }
        log.error("[{}], {}, 查询用户openid失败, 返回信息：{}", TAG, uuid, jsonString);
        JSONObject jsonObject = result.getJSONObject("error");

        return ResponseDTO.fail(jsonObject.getString("desc"));
    }

    /**
     * 查询用户uid
     *
     * @param uuid        uuid
     * @param accessToken accessToken
     * @param appKey      appKey
     * @param appSecret   appSecret
     * @return String
     * @author xujie
     * @since 2021/05/20
     */
    private String getUid(String uuid, String accessToken, String appKey, String appSecret) {
        TreeMap<String, String> treeMap = new TreeMap<>();
        treeMap.put("method", "jingdong.uidbypin.query");
        treeMap.put("access_token", accessToken);
        treeMap.put("app_key", appKey);
        treeMap.put("timestamp", DateUtil.dateFormatToString(new Date(), DateUtil.FORMAT_DEFAULT));
        treeMap.put("360buy_param_json", new JSONObject().toJSONString());
        String sign = getSign(treeMap, appSecret);
        treeMap.put("sign", sign);
        String jsonString = HttpClientsUtil.executeGet(getUrl(treeMap));
        log.info("[{}], {}, 查询用户uid, 返回信息：{}", TAG, uuid, jsonString);
        if (StringUtil.isBlank(jsonString)) {
            return null;
        }
        String responseSuccess = "jingdong_uidbypin_query_response";
        JSONObject result = JSONObject.parseObject(jsonString);
        if (result.containsKey(responseSuccess)) {
            JSONObject response = result.getJSONObject(responseSuccess);
            return response.getString("uid");
        }
        log.error("[{}], {}, 查询用户uid失败, 返回信息：{}", TAG, uuid, jsonString);
        return null;
    }

    /**
     * 查询用户手机号
     *
     * @param uuid        uuid
     * @param accessToken accessToken
     * @param appKey      appKey
     * @param appSecret   appSecret
     * @return String
     * @author xujie
     * @since 2021/05/20
     */
    private String getMobile(String uuid, String appId, String accessToken, String appKey, String appSecret) {

        TreeMap<String, String> treeMap = new TreeMap<>();
        treeMap.put("method", "jingdong.jda.getMobileByToken");
        treeMap.put("access_token", accessToken);
        treeMap.put("app_key", appKey);
        treeMap.put("timestamp", DateUtil.dateFormatToString(new Date(), DateUtil.FORMAT_DEFAULT));
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("app_id", appId);
        treeMap.put("360buy_param_json", jsonObject.toJSONString());
        String sign = getSign(treeMap, appSecret);
        treeMap.put("sign", sign);
        String jsonString = HttpClientsUtil.executeGet(getUrl(treeMap));
        log.info("[{}], {}, 查询用户手机号, 返回信息：{}", TAG, uuid, jsonString);
        if (jsonString == null) {
            return null;
        }
        String responseStr = "jingdong_jda_getMobileByToken_response";
        JSONObject response = JSONObject.parseObject(jsonString);
        if (response.containsKey(responseStr)) {
            String returnTypeStr = "returnType";
            JSONObject returnType = response.getJSONObject(returnTypeStr);
            String dataStr = "data";
            if (returnType.containsKey(dataStr)) {
                JSONObject data = returnType.getJSONObject(dataStr);
                return data.getString("mobile");
            }
        }
        log.error("[{}], {}, 查询用户手机号失败, 返回信息：{}", TAG, uuid, jsonString);
        return null;
    }

    /**
     * 根据openId获取用户信息
     *
     * @param uuid        uuid
     * @param accessToken accessToken
     * @param openId      openId
     * @param appKey      appKey
     * @param appSecret   appSecret
     * @return 京东用户信息
     * @author xujie
     * @since 2021/05/20
     */
    private JdUserInfo getUserInfoByOpenId(String uuid, String accessToken, String openId, String appKey, String appSecret) {

        TreeMap<String, String> treeMap = new TreeMap<>();
        treeMap.put("method", "jingdong.user.getUserInfoByOpenId");
        treeMap.put("access_token", accessToken);
        treeMap.put("app_key", appKey);
        treeMap.put("timestamp", DateUtil.dateFormatToString(new Date(), DateUtil.FORMAT_DEFAULT));
        treeMap.put("v", "2.0");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("openId", openId);
        treeMap.put("360buy_param_json", jsonObject.toJSONString());
        String sign = getSign(treeMap, appSecret);
        treeMap.put("sign", sign);
        String jsonString = HttpClientsUtil.executeGet(getUrl(treeMap));
        log.info("[{}], {}, 根据openId获取用户信息, 返回信息：{}", TAG, uuid, jsonString);
        if (jsonString == null) {
            return null;
        }
        JSONObject result = JSONObject.parseObject(jsonString);
        String responseSuccess = "jingdong_user_getUserInfoByOpenId_response";
        if (result.containsKey(responseSuccess)) {
            JSONObject response = result.getJSONObject(responseSuccess);
            if (response == null) {
                return null;
            }
            String userInfoResultStr = "getuserinfobyappidandopenid_result";
            JSONObject userInfoResult = response.getJSONObject(userInfoResultStr);
            if (userInfoResult == null) {
                return null;
            }
            JSONObject data = userInfoResult.getJSONObject("data");
            if (data == null) {
                return null;
            }
            return JSONObject.parseObject(data.toJSONString(), JdUserInfo.class);
        }
        log.error("[{}], {}, 根据openId获取用户信息失败, 返回信息：{}", TAG, uuid, jsonString);
        return null;
    }

    /**
     * 计算签名
     *
     * @param treeMap treeMap
     * @return 签名
     * @author xujie
     * @since 2021/05/20
     */
    private String getSign(TreeMap<String, String> treeMap, String appSecret) {

        StringBuilder sb = new StringBuilder();
        sb.append(appSecret);
        treeMap.forEach((k, v) -> {
            sb.append(k);
            sb.append(v);
        });
        sb.append(appSecret);
        return DigestUtils.md5Hex(sb.toString());
    }

    /**
     * 得到 url
     *
     * @param treeMap treeMap
     * @return url
     * @author xujie
     * @since 2021/05/20
     */
    private String getUrl(TreeMap<String, String> treeMap) {
        return JDConstant.ROUTER_JSON_URL + HttpClientsUtil.splicingUrlData(treeMap);
    }

    /**
     * 设置UserInfo
     * @param openId
     * @param dio
     * @return
     */
    private UserInfo setUserInfo(String openId,UserAuthLoginDIO dio){
        return UserInfo.builder()
                .userId(null)
                .openId(openId)
                .unionId(openId)
                .type(null)
                .realname(StringUtil.isBlank(dio.getNickName()) ? "京东用户" : dio.getNickName())
                .username(null)
                .nickName(dio.getNickName())
                .avatarSrc(dio.getAvatarUrl())
                .age(null)
                .gender(dio.getSex() == null ? 3 : dio.getSex())
                .country(dio.getCountry())
                .province(dio.getProvince())
                .city(dio.getCity())
                .build();
    }

    /**
     * 设置PlatInfo
     * @param dio
     * @param app
     * @param channelId
     * @return
     */
    private PlatInfo setPlatInfo(UserAuthLoginDIO dio,AppDRO app,Integer channelId){
        return PlatInfo.builder()
                .shopId(dio.getShopId())
                .plat(app.getPlat())
                .channelId(channelId)
                .channelName(getNameByChannelId(channelId))
                .entrance(dio.getEntrance())
                .build();
    }

    /**
     * 设置ThirdAppInfo
     * @param app
     * @return
     */
    private ThirdAppInfo setThirdAppInfo(AppDRO app){
        return ThirdAppInfo.builder()
                .appId(app.getThirdAppId())
                .appName(app.getName())
                .appSecret(app.getThirdAppSecret())
                .build();
    }

    /**
     * 设置UserAuthLoginInfo
     * @param info
     * @param platInfo
     * @param thirdAppInfo
     * @param authPhoneInfo
     * @return
     */
    private UserAuthLoginInfo setUserAuthLoginInfo(UserInfo info,PlatInfo platInfo,ThirdAppInfo thirdAppInfo,UserAuthPhoneInfo authPhoneInfo){
        return UserAuthLoginInfo.builder()
                .userInfo(info)
                .userOtherInfo(new UserOtherInfo())
                .platInfo(platInfo)
                .thirdAppInfo(thirdAppInfo)
                .userPhoneInfo(UserPhoneInfo.builder().mobile(authPhoneInfo.getMobile()).build())
                .build();
    }
}
